/**
 * 后进先出原则
 * 后注册,先监听
 */
'use strict';

class Event {
    constructor () {
        this._events = {};
    }

    /**
     * 获取响应之前上一个路由
     * 注意，一旦页面刚刚路径，修改起来很麻烦
     * @return {String} route
     */
    getEmitBeforeRoute () {
        let routes = getCurrentPages();
        let l = routes.length;
        if (l === 1 || !l) {
            return null
        }
        return routes[l - 2].route || routes[l - 2].__route__;
    }

    beforeOn (name, callback, self) {
        if (!name) {
            console.warn('缺失监听事件名称');
            return false;
        }
        if (!callback) {
            console.warn('空回调函数' + name);
            return false;
        }
        if (!self) {
            console.warn('缺少this参数' + name);
            return false;
        }
        if (!this._events[name]) {
            this._events[name] = [];
        }
        return true;
    }

    /**
     * 订阅
     * @param {String} name 监听事件名称
     * @param {Function} callback 回调函数
     * @param {Object} self 唯一标识
     */
    on (name, callback, self) {
        if (!this.beforeOn(name, callback, self)) {
            return;
        }

        let tuple = [self, callback];
        let eventList = this._events[name];

        eventList.unshift(tuple);

        let num = 0;
        let l = eventList.length;
        for (let i = 0; i < l; i++) {
            if (eventList[i][0] === self) {
                num += 1;
            }
        }
        if (num > 1) {
            console.warn('发现重复绑定' + name);
        }
        if (num === 0) {
            console.warn('绑定失败' + name);
        }
    }

    /**
     * 相同this只能订阅一个, 后一个覆盖前一个
     * 小程序每次实例Page,Component, this不一样,防止App
     * @param {String} name 监听事件名称
     * @param {Function} callback 回调函数
     * @param {any} self 唯一标识
     */
    onnewest (name, callback, self) {
        if (!this.beforeOn(name, callback, self)) {
            return;
        }

        let eventList = this._events[name];
        let l = eventList.length;

        for (let i = 0; i < l; i++) {
            let item = eventList[i];
            if (!item) {
                continue;
            }
            if (item[0] === self) {
                console.error(`移除重复绑定${name}`);
                eventList.splice(i, 1);
                i -= 1;
                l -= 1;
            }
        }

        eventList.unshift([self, callback]);
    }

    /**
     * 相同this下已存在, 不允许被覆盖
     * @param {String} name 监听事件名称
     * @param {Function} callback 回调函数
     * @param {Object} self 唯一标识
     */
    onoldest (name, callback, self) {
        if (!this.beforeOn(name, callback, self)) {
            return;
        }

        let eventList = this._events[name];
        let l = eventList.length;

        for (let i = 0; i < l; i++) {
            let item = eventList[i];
            if (!item) {
                continue;
            }
            if (item[0] === self) {
                console.error(`${name}下注册失败,原因:${self}标识已被注册`);
                return;
            }
        }

        eventList.unshift([self, callback]);
    }

    /**
     * 删除所有标识
     * @param {String} name
     * @param {Object} self
     */
    remove (name, self) {
        let eventList = this._events[name];
        if (!eventList || eventList.length <= 0) {
            return console.error('移除空监听' + name);
        }

        let is = false;
        let l = eventList.length;
        for (let i = 0; i < l; i++) {
            if (eventList[i][0] === self) {
                is = true;
                eventList.splice(i, 1);
                i -= 1;
                l -= 1;
            }
        }
        if (!is) {
            return console.error('移除空监听' + name);
        }
    }

    /**
     * 获取符合条件的name
     * @param {String} name
     */
    getEmitEvent (name) {
        let done = [];
        let eventList = this._events[name];
        if (!eventList || eventList.length <= 0) {
            console.error('空响应' + name);
            return done;
        }

        let l = eventList.length;
        for (let i = 0; i < l; i++) {
            let tuple = eventList[i];
            let _argument = [];

            if (!tuple) {
                console.error('进入循环无响应');
                return done;
            }

            try {
                _argument = [].slice.apply(arguments);
                _argument.shift();
            } catch (err) {
                console.error('emitAll解析数据失败', err);
            }
            try {
                done.push({
                    fun: tuple[1],
                    self: tuple[0],
                    argus: [
                        ..._argument,
                        {
                            index: i,
                            beforeRoute: this.getEmitBeforeRoute()
                        }
                    ]
                });
            } catch (e) {
                console.error('响应失败emitAll', e);
            }
        }
        return done;
    }
    
    /**
     * 发布
     * @param {String} name
     * @param {Object} arguments 额外参数
     *
     * 如果等待一个事件响应,立刻移除,此时下一个index会错乱的
     */
    emitAll () {
        this.getEmitEvent(...arguments).forEach(element => {
            element.fun.apply(element.self, element.argus);
        });
    }

    /**
     * 先监听的先响应
     */
    emitAllByReverse () {
        this.getEmitEvent(...arguments).reverse().forEach(element => {
            element.fun.apply(element.self, element.argus);
        });
    }

    /**
     * 发布 只发布第一个人
     * @param {String} name
     * @param {Object} arguments 额外参数
     */
    emit (name) {
        let eventList = this._events[name];
        if (!eventList || eventList.length <= 0) {
            return console.error('空响应' + name);
        }

        let tuple = eventList[0];
        let _argument = [];

        try {
            _argument = [].slice.apply(arguments);
            _argument.shift();
        } catch (err) {
            console.error('emit解析数据失败', err);
        }
        tuple[1].apply(tuple[0], [
            ..._argument,
            {
                index: 0,
                beforeRoute: this.getEmitBeforeRoute()
            }
        ]);
    }
}

(() => {
    let event = new Event();
    ['on', 'onnewest', 'onoldest', 'remove', 'emitAll', 'emitAllByReverse', 'emit'].forEach(name => {
        Event[name] = function () {
            return event[name].apply(event, arguments);
        };
    });
})();

module.exports = Event;
export default Event;
